﻿' Application developped by Régis Scyeur for Top System Belgium : http://www.topsystem.be
Imports System.Xml
Imports System.Web
Imports System.Text
Imports System.IO
Imports System.Net
Imports System.Diagnostics


Public Class Csta
    ' don't forget to set trusted ip address localhost and [::1], if Your pbx is running locally
    Private Shared _uri As String = "http://localhost"

    Public Shared Property Uri() As String
        Get
            Return _uri
        End Get
        Set(ByVal value As String)
            _uri = value
        End Set
    End Property

    Shared Function MakeCall(ByVal domain As String, ByVal callindDevice As String, ByVal calledDirectoryNumber As String) As String
        Dim makeCallRequest As New CstaMakeCallRequest(domain, callindDevice, calledDirectoryNumber)
        Dim soapRequest As String = makeCallRequest.Serialize

        Dim soapResponse As String = SendRequest(soapRequest)
        Dim makeCallResponse As New CstaMakeCallResponse(soapResponse)
        Return makeCallResponse.CallId
    End Function


    Public Shared Function SendRequest(ByVal soapRequest As String) As String
        Dim soapResponse As String = String.Empty
        Dim buffer As Byte() = Encoding.UTF8.GetBytes(soapRequest)
        Dim request As HttpWebRequest = HttpWebRequest.Create(Uri)
        request.Method = "POST"
        request.ContentType = "application/xml"
        request.ContentLength = buffer.Length

        Try
            Dim requestStream As Stream = request.GetRequestStream()
            requestStream.Write(buffer, 0, buffer.Length)

            Dim response As HttpWebResponse = request.GetResponse()
            If response.StatusCode = HttpStatusCode.OK Then
                Using sr As New StreamReader(response.GetResponseStream)
                    soapResponse = sr.ReadToEnd
                End Using
            Else
                Dim msg As String = String.Format("SendRequest failed : {0}", [Enum].GetName(GetType(HttpStatusCode), response.StatusCode))
                MsgBox(msg)
                WriteToEventLog(msg)
            End If
        Catch ex As Exception
            Dim msg As String = ProcessException(ex)
            MsgBox(msg)
            WriteExceptionToEventLog(ex)
        End Try
        Return soapResponse
    End Function


    Protected Class CstaMakeCallRequest
        Inherits SoapRequest

        Public Domain As String
        Public CallingDevice As String
        Public CalledDirectoryNumber As String

        Sub New(ByVal domain As String, ByVal callingDevice As String, ByVal calledDirectoryNumber As String)
            Me.envType = EnvelopeType.MakeCall
            Me.Domain = domain
            Me.CallingDevice = callingDevice
            Me.CalledDirectoryNumber = calledDirectoryNumber
        End Sub

        Public Overrides Function Serialize() As String
            Dim xmlElmt As XmlElement = Nothing
            Dim xmldoc As XmlDocument = GetEnveloppe(xmlElmt)

            Dim domainElmt As XmlElement = xmldoc.CreateElement("domain")
            domainElmt.InnerText = Me.Domain
            xmlElmt.AppendChild(domainElmt)

            Dim callingDeviceElmt As XmlElement = xmldoc.CreateElement("callingDevice")
            callingDeviceElmt.InnerText = Me.CallingDevice
            xmlElmt.AppendChild(callingDeviceElmt)

            Dim calledDirectoryNumberElmt As XmlElement = xmldoc.CreateElement("calledDirectoryNumber")
            calledDirectoryNumberElmt.InnerText = Me.CalledDirectoryNumber
            xmlElmt.AppendChild(calledDirectoryNumberElmt)

            Dim sReturn As String = xmldoc.OuterXml

            Return sReturn
        End Function
    End Class



    Protected Class CstaMakeCallResponse
        Private _soapInfo As String
        Private _callId As String
        Private _deviceID As String

        Public ReadOnly Property SoapInfo() As String
            Get
                Return Me._soapInfo
            End Get
        End Property

        Public ReadOnly Property CallId() As String
            Get
                Return Me._callId
            End Get
        End Property

        Public ReadOnly Property DeviceID() As String
            Get
                Return Me._deviceID
            End Get
        End Property

        Public Sub New(ByVal soapInfo As String)
            Try
                Dim xmldoc As New XmlDocument
                xmldoc.LoadXml(soapInfo)
                Me._soapInfo = xmldoc.OuterXml

                Dim CallingDeviceNode As XmlNode = xmldoc.GetElementsByTagName("csta:callingDevice")(0)
                For Each childNode As XmlNode In CallingDeviceNode.ChildNodes
                    Select Case childNode.Name
                        Case "csta:callID"
                            Me._callId = childNode.InnerText
                        Case "csta:deviceID"
                            Me._deviceID = childNode.InnerText
                    End Select
                Next
            Catch ex As Exception
                Debug.Write(ex.ToString)
            End Try
        End Sub
    End Class

    Protected Enum EnvelopeType
        MakeCall
        ClearCall
    End Enum

    Protected MustInherit Class SoapRequest
        Protected envType As EnvelopeType

        Private Shared _SoapEnvelope As String = ""
        Private Shared ReadOnly Property SoapEnvelope() As String
            Get
                If String.IsNullOrEmpty(_SoapEnvelope) Then
                    Dim sw As New StringWriter
                    sw.WriteLine("<?xml version=""1.0"" standalone=""yes""?>")
                    sw.WriteLine("<env:Envelope xmlns:env=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:sns=""http://www.pbxnsip.com/soap/pbx"">")
                    sw.WriteLine("<env:Body/>")
                    sw.WriteLine("</env:Envelope>")
                    _SoapEnvelope = sw.ToString
                End If
                Return _SoapEnvelope
            End Get
        End Property

        Protected Function GetEnveloppe(ByRef elmt As XmlElement) As XmlDocument
            Dim XmlDoc As New XmlDocument
            XmlDoc.LoadXml(SoapEnvelope)
            Dim bodyNode As XmlNode = XmlDoc.GetElementsByTagName("env:Body")(0)
            elmt = XmlDoc.CreateElement("sns", [Enum].Parse(GetType(EnvelopeType), envType).ToString, "http://www.pbxnsip.com/soap/pbx")
            bodyNode.AppendChild(elmt)
            Return XmlDoc
        End Function


        Public MustOverride Function Serialize() As String


    End Class
    Private Shared Function WriteExceptionToEventLog(ByVal ex As Exception) As Boolean
        Dim bRetval As Boolean = True
        Dim logName As String = "pbxnsip"
        Dim appName As String = "pbxnsip Helper"
        Dim entry As String = ProcessException(ex)

        If Not String.IsNullOrEmpty(entry) Then
            Try
                If Not EventLog.Exists(logName) Then
                    EventLog.CreateEventSource(appName, logName)
                End If
                EventLog.WriteEntry(appName, entry, EventLogEntryType.Error)
            Catch o As Exception
                bRetval = False
            End Try
        End If
        Return bRetval
    End Function

    Private Shared Function WriteToEventLog(ByVal msg As String) As Boolean
        Dim bRetval As Boolean = True
        Dim logName As String = "pbxnsip"
        Dim appName As String = "pbxnsip Helper"

        If Not String.IsNullOrEmpty(msg) Then
            Dim objEventLog As New EventLog(logName)
            Try
                objEventLog.Source = appName
                objEventLog.WriteEntry(msg, EventLogEntryType.Information)
            Catch
                bRetval = False
            End Try
        End If
        Return bRetval
    End Function

    Private Shared Function ProcessException(ByVal ex As Exception) As String
        Dim msg As String = String.Empty
        Do While Not IsNothing(ex.InnerException)
            ex = ex.InnerException
        Loop
        msg = ex.Message & vbCrLf & ex.StackTrace
        Return msg
    End Function


End Class
